{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2.3 $H(curl)$ and $H(div)$ function spaces\n",
    "\n",
    "Scalar and vectorial elements in NGSolve:\n",
    "\n",
    "*Standard* continuous $H^1$ elements:\n",
    "\n",
    "<center>\n",
    "![](resources/nodalelement.png)\n",
    "</center>\n",
    "\n",
    "Nedelec's tangentially-continuous $H(curl)$-conforming edge elements:\n",
    "\n",
    "<center>\n",
    "![](resources/edgeelement.png)\n",
    "</center>\n",
    "\n",
    "Raviart-Thomas normally-continuous $H(div)$-conforming face elements:\n",
    "\n",
    "<center>\n",
    "![](resources/faceelement.png)\n",
    "</center>\n",
    "\n",
    "Discontinuous $L_2$ elements:\n",
    "\n",
    "<center>\n",
    "![](resources/l2element.png)\n",
    "</center>\n",
    "\n",
    "These vector-valued spaces allow to represent physical quantities which are either normally or tangentially continuous.\n",
    "\n",
    "The finite element spaces are related by the de Rham complex:\n",
    "\n",
    "$$\n",
    "\\DeclareMathOperator{\\Grad}{grad}\n",
    "\\DeclareMathOperator{\\Curl}{curl}\n",
    "\\DeclareMathOperator{\\Div}{div}\n",
    "\\begin{array}{ccccccc}\n",
    "H^1      &  \\stackrel{\\Grad}{\\longrightarrow}          &\n",
    "H(\\Curl) &  \\stackrel{\\Curl}{\\longrightarrow}   &\n",
    "H(\\Div)  &  \\stackrel{\\Div}{\\longrightarrow}    & \n",
    "L^2                                                                                    \\\\[8pt]\n",
    "\\bigcup  &                  &\n",
    "\\bigcup  &                  &\n",
    "\\bigcup  &                  &\n",
    "\\bigcup                              \\\\[8pt]\n",
    " W_{h}                   &      \n",
    "\\stackrel{\\Grad}{\\longrightarrow}          &\n",
    " V_{h }       &     \n",
    " \\stackrel{\\Curl}{\\longrightarrow}   &\n",
    " Q_{h}          &      \n",
    "\\stackrel{\\Div}{\\longrightarrow}    & \n",
    "S_{h}  \\:                                                               \n",
    " \\\\[3ex]\n",
    "\\end{array}\n",
    "$$\n",
    "\n",
    "NGSolve supports these elements of arbitrary order, on all common element shapes (trigs, quads, tets, prisms, pyramids, hexes). Elements may be curved."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import netgen.gui\n",
    "%gui tk\n",
    "from ngsolve import *\n",
    "from netgen.geom2d import unit_square\n",
    "from netgen.csg import unit_cube\n",
    "mesh = Mesh(unit_square.GenerateMesh(maxh=0.3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Generate a higher order $H^1$-space. We first explore its different types of basis functions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "order=3\n",
    "fes = H1(mesh, order=order)\n",
    "gfu = GridFunction(fes)\n",
    "Draw(gfu)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The first #vertices basis functions are hat-functions. By setting the solution vector to a unit-vector, we may look at the individual basis functions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "SetVisualization(min=0, max=1)\n",
    "gfu.vec[:] = 0\n",
    "# vertex nr:\n",
    "gfu.vec[17] = 1\n",
    "Redraw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The next are edge-bubbles, where we have $(order-1)$ basis functions per edge. A `NodeId` object refers to a particular vertex, edge, face or cell node in the mesh. We can ask for the degrees of freedom on a node:  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "edge_dofs = (44, 45)\n"
     ]
    }
   ],
   "source": [
    "# basis functions on edge nr:\n",
    "edge_dofs = fes.GetDofNrs(NodeId(EDGE,10))\n",
    "print(\"edge_dofs =\", edge_dofs)\n",
    "SetVisualization(min=-0.05, max=0.05)\n",
    "gfu.vec[:] = 0\n",
    "gfu.vec[edge_dofs[0]] = 1\n",
    "Redraw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we have $(p-1)(p-2)/2$ inner basis functions on every triangle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "trig_dofs =  (130,)\n"
     ]
    }
   ],
   "source": [
    "trig_dofs = fes.GetDofNrs(NodeId(FACE,0))\n",
    "print(\"trig_dofs = \", trig_dofs)\n",
    "SetVisualization(min=0, max=0.03)\n",
    "gfu.vec[:] = 0\n",
    "gfu.vec[trig_dofs[0]] = 1\n",
    "Redraw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `FESpace` also maintains information about local dofs, interface dofs and wire-basket dofs for the BDDC preconditioner:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "1 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "2 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "3 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "4 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "5 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "6 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "7 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "8 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "9 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "10 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "11 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "12 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "13 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "14 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "15 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "16 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "17 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "18 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "19 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "20 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "21 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "22 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "23 : COUPLING_TYPE.WIREBASKET_DOF\n",
      "24 : COUPLING_TYPE.INTERFACE_DOF\n",
      "25 : COUPLING_TYPE.INTERFACE_DOF\n",
      "26 : COUPLING_TYPE.INTERFACE_DOF\n",
      "27 : COUPLING_TYPE.INTERFACE_DOF\n",
      "28 : COUPLING_TYPE.INTERFACE_DOF\n",
      "29 : COUPLING_TYPE.INTERFACE_DOF\n",
      "30 : COUPLING_TYPE.INTERFACE_DOF\n",
      "31 : COUPLING_TYPE.INTERFACE_DOF\n",
      "32 : COUPLING_TYPE.INTERFACE_DOF\n",
      "33 : COUPLING_TYPE.INTERFACE_DOF\n",
      "34 : COUPLING_TYPE.INTERFACE_DOF\n",
      "35 : COUPLING_TYPE.INTERFACE_DOF\n",
      "36 : COUPLING_TYPE.INTERFACE_DOF\n",
      "37 : COUPLING_TYPE.INTERFACE_DOF\n",
      "38 : COUPLING_TYPE.INTERFACE_DOF\n",
      "39 : COUPLING_TYPE.INTERFACE_DOF\n",
      "40 : COUPLING_TYPE.INTERFACE_DOF\n",
      "41 : COUPLING_TYPE.INTERFACE_DOF\n",
      "42 : COUPLING_TYPE.INTERFACE_DOF\n",
      "43 : COUPLING_TYPE.INTERFACE_DOF\n",
      "44 : COUPLING_TYPE.INTERFACE_DOF\n",
      "45 : COUPLING_TYPE.INTERFACE_DOF\n",
      "46 : COUPLING_TYPE.INTERFACE_DOF\n",
      "47 : COUPLING_TYPE.INTERFACE_DOF\n",
      "48 : COUPLING_TYPE.INTERFACE_DOF\n",
      "49 : COUPLING_TYPE.INTERFACE_DOF\n",
      "50 : COUPLING_TYPE.INTERFACE_DOF\n",
      "51 : COUPLING_TYPE.INTERFACE_DOF\n",
      "52 : COUPLING_TYPE.INTERFACE_DOF\n",
      "53 : COUPLING_TYPE.INTERFACE_DOF\n",
      "54 : COUPLING_TYPE.INTERFACE_DOF\n",
      "55 : COUPLING_TYPE.INTERFACE_DOF\n",
      "56 : COUPLING_TYPE.INTERFACE_DOF\n",
      "57 : COUPLING_TYPE.INTERFACE_DOF\n",
      "58 : COUPLING_TYPE.INTERFACE_DOF\n",
      "59 : COUPLING_TYPE.INTERFACE_DOF\n",
      "60 : COUPLING_TYPE.INTERFACE_DOF\n",
      "61 : COUPLING_TYPE.INTERFACE_DOF\n",
      "62 : COUPLING_TYPE.INTERFACE_DOF\n",
      "63 : COUPLING_TYPE.INTERFACE_DOF\n",
      "64 : COUPLING_TYPE.INTERFACE_DOF\n",
      "65 : COUPLING_TYPE.INTERFACE_DOF\n",
      "66 : COUPLING_TYPE.INTERFACE_DOF\n",
      "67 : COUPLING_TYPE.INTERFACE_DOF\n",
      "68 : COUPLING_TYPE.INTERFACE_DOF\n",
      "69 : COUPLING_TYPE.INTERFACE_DOF\n",
      "70 : COUPLING_TYPE.INTERFACE_DOF\n",
      "71 : COUPLING_TYPE.INTERFACE_DOF\n",
      "72 : COUPLING_TYPE.INTERFACE_DOF\n",
      "73 : COUPLING_TYPE.INTERFACE_DOF\n",
      "74 : COUPLING_TYPE.INTERFACE_DOF\n",
      "75 : COUPLING_TYPE.INTERFACE_DOF\n",
      "76 : COUPLING_TYPE.INTERFACE_DOF\n",
      "77 : COUPLING_TYPE.INTERFACE_DOF\n",
      "78 : COUPLING_TYPE.INTERFACE_DOF\n",
      "79 : COUPLING_TYPE.INTERFACE_DOF\n",
      "80 : COUPLING_TYPE.INTERFACE_DOF\n",
      "81 : COUPLING_TYPE.INTERFACE_DOF\n",
      "82 : COUPLING_TYPE.INTERFACE_DOF\n",
      "83 : COUPLING_TYPE.INTERFACE_DOF\n",
      "84 : COUPLING_TYPE.INTERFACE_DOF\n",
      "85 : COUPLING_TYPE.INTERFACE_DOF\n",
      "86 : COUPLING_TYPE.INTERFACE_DOF\n",
      "87 : COUPLING_TYPE.INTERFACE_DOF\n",
      "88 : COUPLING_TYPE.INTERFACE_DOF\n",
      "89 : COUPLING_TYPE.INTERFACE_DOF\n",
      "90 : COUPLING_TYPE.INTERFACE_DOF\n",
      "91 : COUPLING_TYPE.INTERFACE_DOF\n",
      "92 : COUPLING_TYPE.INTERFACE_DOF\n",
      "93 : COUPLING_TYPE.INTERFACE_DOF\n",
      "94 : COUPLING_TYPE.INTERFACE_DOF\n",
      "95 : COUPLING_TYPE.INTERFACE_DOF\n",
      "96 : COUPLING_TYPE.INTERFACE_DOF\n",
      "97 : COUPLING_TYPE.INTERFACE_DOF\n",
      "98 : COUPLING_TYPE.INTERFACE_DOF\n",
      "99 : COUPLING_TYPE.INTERFACE_DOF\n",
      "100 : COUPLING_TYPE.INTERFACE_DOF\n",
      "101 : COUPLING_TYPE.INTERFACE_DOF\n",
      "102 : COUPLING_TYPE.INTERFACE_DOF\n",
      "103 : COUPLING_TYPE.INTERFACE_DOF\n",
      "104 : COUPLING_TYPE.INTERFACE_DOF\n",
      "105 : COUPLING_TYPE.INTERFACE_DOF\n",
      "106 : COUPLING_TYPE.INTERFACE_DOF\n",
      "107 : COUPLING_TYPE.INTERFACE_DOF\n",
      "108 : COUPLING_TYPE.INTERFACE_DOF\n",
      "109 : COUPLING_TYPE.INTERFACE_DOF\n",
      "110 : COUPLING_TYPE.INTERFACE_DOF\n",
      "111 : COUPLING_TYPE.INTERFACE_DOF\n",
      "112 : COUPLING_TYPE.INTERFACE_DOF\n",
      "113 : COUPLING_TYPE.INTERFACE_DOF\n",
      "114 : COUPLING_TYPE.INTERFACE_DOF\n",
      "115 : COUPLING_TYPE.INTERFACE_DOF\n",
      "116 : COUPLING_TYPE.INTERFACE_DOF\n",
      "117 : COUPLING_TYPE.INTERFACE_DOF\n",
      "118 : COUPLING_TYPE.INTERFACE_DOF\n",
      "119 : COUPLING_TYPE.INTERFACE_DOF\n",
      "120 : COUPLING_TYPE.INTERFACE_DOF\n",
      "121 : COUPLING_TYPE.INTERFACE_DOF\n",
      "122 : COUPLING_TYPE.INTERFACE_DOF\n",
      "123 : COUPLING_TYPE.INTERFACE_DOF\n",
      "124 : COUPLING_TYPE.INTERFACE_DOF\n",
      "125 : COUPLING_TYPE.INTERFACE_DOF\n",
      "126 : COUPLING_TYPE.INTERFACE_DOF\n",
      "127 : COUPLING_TYPE.INTERFACE_DOF\n",
      "128 : COUPLING_TYPE.INTERFACE_DOF\n",
      "129 : COUPLING_TYPE.INTERFACE_DOF\n",
      "130 : COUPLING_TYPE.LOCAL_DOF\n",
      "131 : COUPLING_TYPE.LOCAL_DOF\n",
      "132 : COUPLING_TYPE.LOCAL_DOF\n",
      "133 : COUPLING_TYPE.LOCAL_DOF\n",
      "134 : COUPLING_TYPE.LOCAL_DOF\n",
      "135 : COUPLING_TYPE.LOCAL_DOF\n",
      "136 : COUPLING_TYPE.LOCAL_DOF\n",
      "137 : COUPLING_TYPE.LOCAL_DOF\n",
      "138 : COUPLING_TYPE.LOCAL_DOF\n",
      "139 : COUPLING_TYPE.LOCAL_DOF\n",
      "140 : COUPLING_TYPE.LOCAL_DOF\n",
      "141 : COUPLING_TYPE.LOCAL_DOF\n",
      "142 : COUPLING_TYPE.LOCAL_DOF\n",
      "143 : COUPLING_TYPE.LOCAL_DOF\n",
      "144 : COUPLING_TYPE.LOCAL_DOF\n",
      "145 : COUPLING_TYPE.LOCAL_DOF\n",
      "146 : COUPLING_TYPE.LOCAL_DOF\n",
      "147 : COUPLING_TYPE.LOCAL_DOF\n",
      "148 : COUPLING_TYPE.LOCAL_DOF\n",
      "149 : COUPLING_TYPE.LOCAL_DOF\n",
      "150 : COUPLING_TYPE.LOCAL_DOF\n",
      "151 : COUPLING_TYPE.LOCAL_DOF\n",
      "152 : COUPLING_TYPE.LOCAL_DOF\n",
      "153 : COUPLING_TYPE.LOCAL_DOF\n",
      "154 : COUPLING_TYPE.LOCAL_DOF\n",
      "155 : COUPLING_TYPE.LOCAL_DOF\n",
      "156 : COUPLING_TYPE.LOCAL_DOF\n",
      "157 : COUPLING_TYPE.LOCAL_DOF\n",
      "158 : COUPLING_TYPE.LOCAL_DOF\n",
      "159 : COUPLING_TYPE.LOCAL_DOF\n"
     ]
    }
   ],
   "source": [
    "for i in range(fes.ndof):\n",
    "    print (i,\":\", fes.CouplingType(i))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## $H(curl)$ finite element space"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In NGSolve we use hierarchical high order finite element basis functions with node-wise exact sequences. The lowest order space $W_{l.o}$ is the edge-element space:\n",
    "\n",
    "$$ \n",
    "\\begin{array}{rcll}\n",
    "W_{hp} & = & W_{p=1} + \\sum_E W_E + \\sum_F W_F + \\sum_C W_C & \\subset H^1 \\\\[0.5em]\n",
    "V_{hp} & = & W_{l.o} + \\sum_E V_E + \\sum_F V_F + \\sum_C V_C & \\subset H(curl) \n",
    "\\end{array}\n",
    "$$\n",
    "\n",
    "where the edge, face and cell blocks are compatible in the sense that\n",
    "\n",
    "$$\n",
    "\\nabla W_E = V_E, \\quad \\nabla W_F \\subset V_F, \\quad \\nabla W_C \\subset V_C\n",
    "$$\n",
    "\n",
    "We obtain this by using gradients of $H^1$ basis functions as $H(curl)$ basis functions, and some more (see thesis Sabine Zaglmayr):\n",
    "\n",
    "$$ \n",
    "\\begin{array}{rcl}\n",
    "V_E & = & \\text{span} \\{ \\nabla \\varphi_{E,i}^{H^1} \\} \\\\\n",
    "V_F & = & \\text{span} \\{ \\nabla \\varphi_{F,i}^{H^1} \\cup \\widetilde \\varphi_{F,i}^{H(curl)} \\} \\\\\n",
    "V_C & = & \\text{span} \\{ \\nabla \\varphi_{C,i}^{H^1} \\cup \\widetilde \\varphi_{C,i}^{H(curl)} \\} \n",
    "\\end{array}\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "fes = HCurl(mesh, order=2)\n",
    "uc = GridFunction(fes, name=\"uc\")\n",
    "Draw (uc)\n",
    "Draw (curl(uc), mesh, \"curl\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "edgedofs:  (10, 73, 74)\n"
     ]
    }
   ],
   "source": [
    "edge_dofs = fes.GetDofNrs(NodeId(EDGE,10))\n",
    "print (\"edgedofs: \", edge_dofs)\n",
    "uc.vec[:] = 0\n",
    "uc.vec[edge_dofs[0]] = 1\n",
    "Redraw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "look at them by activating *Draw Surface Vectors*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "facedofs:  (234, 235, 236)\n"
     ]
    }
   ],
   "source": [
    "face_dofs = fes.GetDofNrs(NodeId(FACE,10))\n",
    "print (\"facedofs: \", face_dofs)\n",
    "uc.vec[:] = 0\n",
    "uc.vec[face_dofs[0]] = 1\n",
    "Redraw()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## $H(div)$ finite element space"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "fes = HDiv(mesh, order=2)\n",
    "ud = GridFunction(fes, name=\"ud\")\n",
    "Draw (ud)\n",
    "Draw (div(ud), mesh, \"div\")\n",
    "ud.vec[:] = 0\n",
    "ud.vec[10] = 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The function spaces know their canonical derivatives. These operations are efficiently implemented by transformation from the reference element."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('div', 'curl')"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ud.derivname, uc.derivname"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "tags": [
     "raises-exception"
    ]
   },
   "outputs": [
    {
     "ename": "Exception",
     "evalue": "cannot form div",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mException\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-12-3853ecb1c0ea>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mdiv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/gitlab/install/netgen/lib/python3/dist-packages/ngsolve/utils.py\u001b[0m in \u001b[0;36mdiv\u001b[0;34m(func)\u001b[0m\n\u001b[1;32m     82\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     83\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0madd\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 84\u001b[0;31m     \u001b[0;32mraise\u001b[0m \u001b[0mException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"cannot form div\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     85\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     86\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mException\u001b[0m: cannot form div"
     ]
    }
   ],
   "source": [
    "div(uc)    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Also the element-wise gradient of H(div) and H(curl) functions is needed for some methods. \n",
    "They are made available by numerical differentiation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "coef N6ngcomp31GridFunctionCoefficientFunctionE, real, dims = 2 x 2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print (grad(ud))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "we can query the available operators"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['grad', 'dual']\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    print (ud.Operators())\n",
    "except:\n",
    "    print (\"need newer NGSolve version\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  },
  "nbsphinx": {
   "allow_errors": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
